﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AzureGames.Data;
using AzureGames.Domain.Models;
using AzureGames.Domain.Contracts;
using AzureGames.Model;

namespace AzureGames.Domain.Handlers
{
    /// <summary>
    /// used to return a model containing the options to start a game of a specified game definition in relation to the current player
    /// </summary>
    public class GetGamePlayOptions
    {
        private readonly IGameDefinitionRepository _gameDefinitionRepository;
        private readonly IPlayerRepository _playerRepository;
        private readonly IAIPlayerRepository _aiPlayerRepository;
        private readonly IBoardRepository _boardRepository;

        public GetGamePlayOptions(IGameDefinitionRepository gameDefinitionRepository, IPlayerRepository playerRepository, IBoardRepository boardRepository, IAIPlayerRepository aiplayerRepository)
        {
            _gameDefinitionRepository = gameDefinitionRepository;
            _playerRepository = playerRepository;
            _boardRepository = boardRepository;
            _aiPlayerRepository = aiplayerRepository;
        }

        public virtual GamePlayOptions Execute(int gameDefinitionID, string playerID, int maxOpponents)
        {
            try
            {
                List<GamePlayer> aiPlayers = new List<GamePlayer>();
                List<GamePlayer> contactPlayers = new List<GamePlayer>();
                List<GamePlayer> challengePlayers = new List<GamePlayer>();

                List<string> messages = new List<string>();

                List<ActiveGame> activeGames = new List<ActiveGame>();

                Model.GameDefinition gameDefinition = _gameDefinitionRepository.GetGameDefinition(gameDefinitionID);
                Player player = _playerRepository.GetPlayer(playerID);

                if (player is User)
                {
                    // if the player is authenticated
                    //   multi-player options including challenging a particular player
                    //   from contacts or by players with a ranking close to the current player

                    // check to see if there are existing games
                    IEnumerable<Board> activeBoards = _boardRepository.GetActiveGames(gameDefinitionID, playerID);

                    foreach (var activeBoard in activeBoards)
                    {
                        var players = new List<GamePlayer>(activeBoard.PlayerIDs.Select(pID => new GamePlayer(_playerRepository.GetPlayer(pID))));
                        activeGames.Add(new ActiveGame(activeBoard, players));
                    }
                }

                if (player is AnonymousPlayer)
                {
                    // if the player is anonymous
                    //   message encouraging log in in order to be play multi-player and to be ranked against other players
                    messages.Add("Login to be able to challenge other players.");
                    messages.Add("Create a user to track your games against other players.");
                }

                // all players - ability to play a single player game against a list of AI
                aiPlayers.AddRange(_aiPlayerRepository.GetAIPlayers(gameDefinitionID).Select(p => new GamePlayer(p)));

                return new GamePlayOptions(gameDefinition, new GamePlayer(player), aiPlayers, challengePlayers, contactPlayers, messages, activeGames);
            }
            catch (InvalidOperationException e)
            {
                throw new BusinessServicesException("Unable to retrieve game definition from database.", e);
            }
        }
    }
}
